﻿using System.Diagnostics.Contracts;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using HtmlAgilityPack;

namespace Arachnophile
{
    /// <summary>
    /// X/HTML lenient processing extensions.
    /// </summary>
    public static class XhtmlEx
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static HtmlDocument Html(this byte[] source)
        {
            Contract.Requires(source != null);

            var html = new HtmlDocument();
            html.Load(source.Stream());
            return html;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static XDocument Xhtml(this byte[] source)
        {
            Contract.Requires(source != null);

            return source.Html().Xhtml();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static HtmlDocument Html(this string source)
        {
            Contract.Requires(source != null);

            var html = new HtmlDocument();
            html.LoadHtml(source);
            return html;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static XDocument Xhtml(this HtmlDocument source)
        {
            Contract.Requires(source != null);

            return source.Xtext().Xml();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<XDocument> Xhtml(this IEnumerable<HtmlDocument> source)
        {
            Contract.Requires(source != null);

            return source.Select(Xhtml);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<HtmlDocument> Html(this IEnumerable<string> source)
        {
            Contract.Requires(source != null);

            return source.Select(Html);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static XDocument Xhtml(this string source)
        {
            Contract.Requires(source != null);

            return source.Html().Xhtml();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<XDocument> Xhtml(this IEnumerable<string> source)
        {
            Contract.Requires(source != null);

            return source.Select(Xhtml);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<XDocument> Xhtml(this IEnumerable<byte[]> source)
        {
            Contract.Requires(source != null);

            return source.Select(Xhtml);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string Text(this HtmlDocument source)
        {
            Contract.Requires(source != null);

            using (var temp = new MemoryStream())
            {
                source.Save(temp);
                temp.Position = 0;
                using (var reader = new StreamReader(temp))
                {
                    return reader.ReadToEnd();
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string Xtext(this HtmlDocument source)
        {
            Contract.Requires(source != null);

            var enc = Encoding.UTF8;
            using (var temp = new MemoryStream())
            {
                source.OptionOutputAsXml = true;
                source.OptionDefaultStreamEncoding = enc;
                using (var writer = new XmlTextWriter(temp, enc))
                {
                    source.Save(writer);
                    temp.Position = 0;
                    using (var reader = new StreamReader(temp))
                    {
                        return reader.ReadToEnd();
                    }
                }
            }
        }
    }
}
